package com.devops.admin.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.devops.admin.mapper.DOSExportDataJobMapper;
import com.devops.admin.model.DOSExportDataJob;
import com.devops.admin.model.ExportDataJobBatch;
import com.devops.admin.model.Pagination;
import com.devops.admin.model.TableResult;
import com.devops.admin.po.ExportDataJobBatchPo;
import com.devops.admin.service.DOSExportDataJobService;
import com.devops.admin.service.ExportDataJobBatchService;
import com.devops.admin.mapper.ExportDataJobBatchMapper;
import com.devops.admin.vo.DOSPageVo;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
* @author Dell
* @description 针对表【dos_export_data_job_batch(拉去数据批量任务)】的数据库操作Service实现
* @createDate 2024-10-14 11:11:43
*/
@Service
public class ExportDataJobBatchServiceImpl extends ServiceImpl<ExportDataJobBatchMapper, ExportDataJobBatch>
    implements ExportDataJobBatchService{

    @Resource
    private DOSExportDataJobService exportDataJobService;

    @Resource
    private DOSExportDataJobMapper exportDataJobMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createBatch(ExportDataJobBatch exportDataJobBatch) {
        JSONArray variables = JSONUtil.parseArray(exportDataJobBatch.getVariableList());
        List<DOSExportDataJob> jobList = new ArrayList<>();

        save(exportDataJobBatch);
        for (Object variable : variables) {
            DOSExportDataJob exportDataJob = new DOSExportDataJob();
            BeanUtil.copyProperties(exportDataJobBatch, exportDataJob, "id", "name");
            String nameSuffix = getNameSuffix(exportDataJobBatch.getVariableKeys(), variable);
            String jobName = exportDataJobBatch.getName() + nameSuffix;
            exportDataJob.setName(jobName);
            exportDataJob.setBatchId(exportDataJobBatch.getId());
            exportDataJob.setVariables(variable);
            exportDataJob.setType(2);
            jobList.add(exportDataJob);
        }
        return exportDataJobService.saveBatch(jobList);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatch(ExportDataJobBatch exportDataJobBatch) {
        checkVariableKeys(exportDataJobBatch);
        updateJobList(exportDataJobBatch);
        return updateBatchConfig(exportDataJobBatch);
    }

    private void checkVariableKeys(ExportDataJobBatch exportDataJobBatch) {
        ExportDataJobBatch currentBatch = getById(exportDataJobBatch.getId());
        if (!exportDataJobBatch.getVariableKeys().equals(currentBatch.getVariableKeys())) {
            throw new RuntimeException("变量key不能修改");
        }
    }


    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchConfig(ExportDataJobBatch exportDataJobBatch) {
        List<DOSExportDataJob> updateList = exportDataJobService.list(
                new LambdaQueryWrapper<DOSExportDataJob>()
                        .eq(DOSExportDataJob::getBatchId, exportDataJobBatch.getId())
        );
        updateList.forEach(job -> {
            BeanUtil.copyProperties(exportDataJobBatch, job, "id", "name");
            String nameSuffix = getNameSuffix(exportDataJobBatch.getVariableKeys(), job.getVariables());
            String jobName = exportDataJobBatch.getName() + nameSuffix;
            job.setName(jobName);
            job.setVariables(null);
            exportDataJobService.updateById(job);
        });
        return updateById(exportDataJobBatch);
    }

    @NotNull
    private static String getNameSuffix(String variableKeys, Object variable) {
        JSONObject variableJson = JSONUtil.parseObj(variable);
        String[] keyArray = variableKeys.split(",");
        return Arrays.stream(keyArray)
                .map(key -> "_" + variableJson.get(key))
                .collect(Collectors.joining());
    }


    @Transactional(rollbackFor = Exception.class)
    public boolean updateJobList(ExportDataJobBatch exportDataJobBatch) {
        JSONArray variables = JSONUtil.parseArray(exportDataJobBatch.getVariableList());
        List<DOSExportDataJob> newJobList = new ArrayList<>();
        List<DOSExportDataJob> deleteJobList = new ArrayList<>();

        List<Object> newVariableList = new ArrayList<>(variables);
        List<Object> currentVariableList = exportDataJobService
                .list(new LambdaQueryWrapper<DOSExportDataJob>().eq(DOSExportDataJob::getBatchId, exportDataJobBatch.getId()))
                .stream().map(job -> JSONUtil.parseObj(job.getVariables())).collect(Collectors.toList());

        List<Object> addVariableList = new ArrayList<>(newVariableList);
        List<Object> deleteVariableList = new ArrayList<>(currentVariableList);

        addVariableList.removeAll(currentVariableList);
        deleteVariableList.removeAll(newVariableList);

        exportDataJobBatch = getById(exportDataJobBatch.getId());

        for (Object variable : addVariableList) {
            DOSExportDataJob exportDataJob = new DOSExportDataJob();
            BeanUtil.copyProperties(exportDataJobBatch, exportDataJob, "id");
            String nameSuffix = getNameSuffix(exportDataJobBatch.getVariableKeys(), variable);
            String jobName = exportDataJobBatch.getName() + nameSuffix;
            exportDataJob.setName(jobName);
            exportDataJob.setBatchId(exportDataJobBatch.getId());
            exportDataJob.setVariables(JSONUtil.parseObj(variable));
            exportDataJob.setType(2);
            newJobList.add(exportDataJob);
        }
        exportDataJobService.saveBatch(newJobList);
        if (exportDataJobBatch.getActive()) {
            newJobList.forEach(job -> exportDataJobService.startOrPauseExportDataJob(job.getBatchId(), true));
        }

        for (Object variable : deleteVariableList) {
            List<DOSExportDataJob> list =
                    exportDataJobMapper.listByBatchIdAndVaiables(exportDataJobBatch.getId(), variable);
            deleteJobList.addAll(list);
        }
        deleteJobList.forEach(job -> exportDataJobService.stopAndRemove(job.getId()));

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatch(Integer batchId) {
        List<DOSExportDataJob> jobList =
                exportDataJobService.list(new LambdaQueryWrapper<DOSExportDataJob>().eq(DOSExportDataJob::getBatchId, batchId));
        jobList.forEach(job -> exportDataJobService.stopAndRemove(job.getId()));
        ExportDataJobBatch exportDataJobBatch = getById(batchId);
        exportDataJobBatch.setActive(false);
        updateById(exportDataJobBatch);
        return removeById(batchId);
    }

    @Override
    public TableResult<ExportDataJobBatchPo> getExportDataJobBatchList(ExportDataJobBatch exportDataJobBatch, DOSPageVo pageVo) {
        Page<ExportDataJobBatchPo> page = new Page<>(pageVo.getPageNum(), pageVo.getPageSize());
        List<ExportDataJobBatchPo> list = baseMapper.getExportDataJobBatchList(exportDataJobBatch, page);
        Map<Integer, List<DOSExportDataJob>> jobMap = exportDataJobService.lambdaQuery()
                .in(DOSExportDataJob::getBatchId, list.stream().map(ExportDataJobBatchPo::getId).collect(Collectors.toList()))
                .orderByAsc(DOSExportDataJob::getId)
                .list()
                .stream()
                .collect(Collectors.groupingBy(DOSExportDataJob::getBatchId));

        list.forEach(batch -> {
            List<DOSExportDataJob> jobs = jobMap.getOrDefault(batch.getId(), Collections.emptyList());
            if (!jobs.isEmpty()) {
                String variableList = JSONUtil.toJsonStr(
                        jobs.stream()
                                .map(job -> JSONUtil.parseObj(job.getVariables()))
                                .collect(Collectors.toList())
                );
                batch.setVariableList(variableList);
            }
        });
        TableResult<ExportDataJobBatchPo> tableResult = new TableResult<>();
        Pagination p = Pagination.builder().pageNum(page.getCurrent()).pageSize(page.getSize()).total(page.getTotal()).build();
        tableResult.setList(list);
        tableResult.setPagination(p);
        return tableResult;
    }

    @Override
    public boolean startOrPauseExportDataJobBatch(Integer batchId, Boolean active) {
        List<DOSExportDataJob> updateList = exportDataJobService.list(
                new LambdaQueryWrapper<DOSExportDataJob>()
                        .eq(DOSExportDataJob::getBatchId, batchId)
        );
        updateList.forEach(job -> exportDataJobService.startOrPauseExportDataJob(job.getId(), active));

        ExportDataJobBatch exportDataJobBatch = getById(batchId);
        exportDataJobBatch.setActive(active);
        return updateById(exportDataJobBatch);
    }
}




